package com.wunu.smartlock1.bluetooth

import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import com.clj.fastble.BleManager
import com.clj.fastble.callback.BleGattCallback
import com.clj.fastble.callback.BleNotifyCallback
import com.clj.fastble.callback.BleWriteCallback
import com.clj.fastble.data.BleDevice
import com.clj.fastble.exception.BleException
import com.clj.fastble.scan.BleScanRuleConfig
import com.wunu.smartlock1.bluetooth.command.IComand
import com.wunu.smartlock1.util.CommonUtil

/**
 * Created by peiwei on 2018/4/21.
 */
public class WunuBlueManager {
    private enum class WunuBlueDeviceState {
        DISCONNECT,
        CONNECTED,
        NOTIFY
    }
    private var SERVICE_UUID: String = "F8C00001-159F-11E6-92F5-0002A5D5C51B"
    private var NOTIFITY_UUID: String = "F8C00003-159F-11E6-92F5-0002A5D5C51B"
    private var WRITE_UUID: String = "F8C00002-159F-11E6-92F5-0002A5D5C51B"

    private val bleManager: BleManager = BleManager.getInstance()

    private var state: WunuBlueDeviceState = WunuBlueDeviceState.DISCONNECT
    private var command: IComand? = null
    private var currentDevice: BleDevice? = null
    private var currentCallback: ((Map<String, Any>) -> Unit) ? = null
    private  var mapInfo :Map<String, Any>? = null
    constructor() {
        if (!BleManager.getInstance().isSupportBle) {
            System.out.println("该设备不支持蓝牙")
        } else {
            BleManager.getInstance().enableBluetooth()
            val configure = BleScanRuleConfig.Builder()
                    .setScanTimeOut(60000)
                    .build()
            BleManager.getInstance().initScanRule(configure)
        }
    }
    companion object {
        val shared = WunuBlueManager()
    }

public fun getMap(): Map<String, Any>? {
        return mapInfo;
    }
    public fun setCommand(command: IComand){
        this.command = command;
    }
    public fun execute(command: IComand, device: BleDevice, callback: (Map<String, Any>) -> Unit) {
        this.command = command
        this.currentCallback = callback
        connectDevice(device)
    }
    /*
    * 连接设备
    * */
    public fun connectDevice(device: BleDevice) {

        BleManager.getInstance().connect(device, object : BleGattCallback() {
            // 开始连接
            override fun onStartConnect() {
                System.out.println("开始连接设备：" + device.name)
            }

            // 连接失败
            override fun onConnectFail(bleDevice: BleDevice?, exception: BleException?) {
                System.out.println("设备：[" + device.name + "]连接失败,失败原因：" + exception.toString())
                currentCallback?.invoke(mapOf("errMsg" to "连接失败"))
                currentDevice = null
//                currentCallback = null
            }

            // 连接成功
            override fun onConnectSuccess(bleDevice: BleDevice?, gatt: BluetoothGatt?, status: Int) {
                System.out.println("设备：[" + device.name + "]连接成功")
                state = WunuBlueDeviceState.CONNECTED
                currentDevice = device
                checkoutServices(bleDevice!!)

            }
            // 失去连接
            override fun onDisConnected(isActiveDisConnected: Boolean, device: BleDevice?, gatt: BluetoothGatt?, status: Int) {
                System.out.println("设备：[" + device!!.name  + "]断开连接")
                state = WunuBlueDeviceState.DISCONNECT
                bleManager.disconnect(device)
                currentDevice = null;
            }
        })
    }
    /*
    * 查询设备服务列表
    * */
    private fun checkoutServices(bleDevice: BleDevice) {
        val gatt = bleManager.getBluetoothGatt(bleDevice)
        val service = gatt.services.find {
            it.uuid.toString().contains("0000fff0")
        }
        if (service != null) {
            SERVICE_UUID = "0000FFF0-0000-1000-8000-00805F9B34FB"
            NOTIFITY_UUID = "0000FFF7-0000-1000-8000-00805F9B34FB"
            WRITE_UUID = "0000FFF6-0000-1000-8000-00805F9B34FB"
        }
        notifyMessage(bleDevice)
    }
    /*
    * 注册通知
    * */
    private fun notifyMessage(bleDevice: BleDevice) {
        bleManager.notify(bleDevice, SERVICE_UUID, NOTIFITY_UUID, object : BleNotifyCallback() {
            // 注册成功
            override fun onNotifySuccess() {
                state = WunuBlueDeviceState.NOTIFY
                if (command != null) {
                    //System.out.println("notify --> onNotifySuccess");
                    System.out.println("write messae " + bytesToHexString(command!!.payload()))
                    writeMessage(bleDevice, command!!.payload())
                } else {
                    System.out.println("command is null")
                }

            }
            // 注册失败
            override fun onNotifyFailure(exception: BleException?) {


            }
            // 接受数据
            override fun onCharacteristicChanged(data: ByteArray?) {
                System.out.println("receiver data: " + bytesToHexString(data!!))
                if (data == null || data.count() == 0) {
                    return
                }
                System.out.println("receiver data: " + bytesToHexString(data!!))
                val infos = command?.decode(data!!)
                mapInfo = infos;
                CommonUtil.map = infos;
                currentCallback?.invoke(infos!!)
                //断开链接
                bleManager.disconnect(currentDevice);
            }
        })
    }
    /*
    * 向设备写数据
    * */
    private fun writeMessage(bleDevice: BleDevice, data: ByteArray) {
        bleManager.write(bleDevice, SERVICE_UUID, WRITE_UUID, data, object : BleWriteCallback() {
            // 写入成功
            override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
                System.out.println("write success ")
            }
            // 写入失败
            override fun onWriteFailure(exception: BleException?) {
                System.out.println("command: " + command.toString() + "is failed")
            }
        })
    }

    public fun bytesToHexString(byteArray: ByteArray): String {
        var hs = ""
        var stmp = ""
        for (i in 0..byteArray.count()-1) {
            stmp = Integer.toHexString(byteArray[i].toInt().and(0xff))
            if (stmp.length < 2) {
                hs += '0'
            }
            hs += stmp.toUpperCase()
        }
        return hs.toString()
    }
}